/*
 * Galaxium Messenger
 * 
 * Copyright (C) 2003-2007 Philippe Durand <draekz@gmail.com>
 * Copyright (C) 2007 Ben Motmans <ben.motmans@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.IO;
using System.Collections.Generic;

using Gtk;
using Glade;

using Anculus.Core;

using Galaxium.Core;
using Galaxium.Protocol;
using Galaxium.Gui;

namespace Galaxium.Gui.GtkGui
{
	public sealed class SetDisplayImageDialog
	{
		[Widget ("SetDisplayImageDialog")]
		private Dialog _dialog;
		[Widget ("DialogImage")]
		private Image _dialogImage;
		[Widget ("ApplyButton")]
		private Button _applyButton;
		[Widget ("CancelButton")]
		private Button _cancelButton;
		
		private ISession _session;
		private ThumbnailView _myImageView;
		private ThumbnailView _contactImageView;
		private ThumbnailView _defaultImageView;
		private ThumbnailView _otherImageView;
		private IAccountCache _cache;
		private string _selectedImageFilename = String.Empty;
		
		public string Filename { get { return _selectedImageFilename; } }
		
		public SetDisplayImageDialog(ISession session)
		{
			_session = session;
			_cache = CacheUtility.GetAccountCache(_session.Account);
			
			XML.CustomHandler = new XMLCustomWidgetHandler (CreateCustomWidget);
			XML gxml = new XML (GladeUtility.GetGladeResourceStream (typeof (SetDisplayImageDialog).Assembly, "SetDisplayImageDialog.glade"), null, null);
			gxml.Autoconnect (this);
			
			_dialog.Icon = IconUtility.GetIcon ("galaxium-images", IconSizes.Small);
			_dialogImage.FromPixbuf = IconUtility.GetIcon ("galaxium-set-image", IconSizes.Large);
			
			RefreshImages ();
			RefreshContactImages ();
			RefreshDefaultImages ();
			RefreshOtherImages ();
			
			CheckInput();
			
			_dialog.ShowAll();
		}
		
		private Widget CreateCustomWidget (XML gxml, string func_name, string name, string string1, string string2, int int1, int int2)
		{
			if (name == "MyImageView")
			{
				_myImageView = new ThumbnailView ();
				_myImageView.SelectionChanged += new EventHandler(MyImageViewSelectionChanged);
				return _myImageView;
			}
			else if (name == "ContactImageView")
			{
				_contactImageView = new ThumbnailView ();
				_contactImageView.SelectionChanged += new EventHandler(ContactImageViewSelectionChanged);
				return _contactImageView;
			}
			else if (name == "DefaultImageView")
			{
				_defaultImageView = new ThumbnailView ();
				_defaultImageView.SelectionChanged += new EventHandler(DefaultImageViewSelectionChanged);
				return _defaultImageView;
			}
			else if (name == "OtherImageView")
			{
				_otherImageView = new ThumbnailView ();
				_otherImageView.SelectionChanged += new EventHandler(OtherImageViewSelectionChanged);
				return _otherImageView;
			}
			
			return new Label ("ERROR");
		}
		
		private void MyImageViewSelectionChanged (object sender, EventArgs args)
		{
			_selectedImageFilename = _myImageView.GetSelectedImagePath ();
			CheckInput ();
		}
		
		private void ContactImageViewSelectionChanged (object sender, EventArgs args)
		{
			_selectedImageFilename = _contactImageView.GetSelectedImagePath ();
			CheckInput ();
		}
		
		private void DefaultImageViewSelectionChanged (object sender, EventArgs args)
		{
			_selectedImageFilename = _defaultImageView.GetSelectedImagePath ();
			CheckInput ();
		}
		
		private void OtherImageViewSelectionChanged (object sender, EventArgs args)
		{
			_selectedImageFilename = _otherImageView.GetSelectedImagePath ();
			CheckInput ();
		}
		
		private void OnAddButtonClicked (object sender, EventArgs args)
		{
			FileChooserDialog dialog = new ImageFileChooserDialog(_dialog);
			dialog.SetCurrentFolder(Environment.GetFolderPath(Environment.SpecialFolder.Personal));
			
			if (dialog.Run () == (int)ResponseType.Accept)
			{
				System.IO.FileStream file = System.IO.File.OpenRead (dialog.Filename);
				
				if (file.Length > 0)
				{
					byte[] fileBytes = new byte[file.Length];
					file.Read (fileBytes, 0, (int)file.Length);
					
					Gdk.Pixbuf pix = new Gdk.Pixbuf(fileBytes);
					pix = PixbufUtility.GetScaledCroppedPixbuf (pix, 96, 96);
					pix.Save(Path.Combine(_cache.ImagesDirectory, BaseUtility.GetHashedName (dialog.Filename)+".cache"), "png");
				}
				
				file.Close();
			}
			
			dialog.Destroy();
			
			RefreshImages ();
		}
		
		private void OnRemoveButtonClicked (object sender, EventArgs args)
		{
			if (_selectedImageFilename != null && _selectedImageFilename != String.Empty)
			{
				if (File.Exists (_selectedImageFilename))
				{
					File.Delete (_selectedImageFilename);
					RefreshImages();
				}
			}
		}
		
		private void OnRefreshButtonClicked (object sender, EventArgs args)
		{
			RefreshImages ();
		}
		
		private void OnContactRefreshButtonClicked (object sender, EventArgs args)
		{
			RefreshContactImages ();
		}
		
		private void OnOtherRefreshButtonClicked (object sender, EventArgs args)
		{
			RefreshOtherImages ();
		}
		
		private void RefreshImages ()
		{
			_myImageView.ClearFiles();
			
			foreach (string filename in Directory.GetFiles (_cache.ImagesDirectory))
			{
				System.IO.FileStream file = System.IO.File.OpenRead (filename);
				
				if (file.Length > 0)
				{
					byte[] fileBytes = new byte[file.Length];
					file.Read (fileBytes, 0, (int)file.Length);
					
					try
					{
						Gdk.Pixbuf pix = new Gdk.Pixbuf(fileBytes);
						
						_myImageView.InsertFile(filename, PixbufUtility.GetFramedPixbuf(pix, PixbufRendererFrameSize.Huge));
					}
					catch
					{
						Log.Error("Unable to read file format! Ignoring file.");
					}
				}
				
				file.Close();
			}
		}
		
		private void RefreshContactImages ()
		{
			_contactImageView.ClearFiles();
			
			lock (_session.ContactCollection)
			{
				foreach (IContact contact in _session.ContactCollection)
				{
					IDisplayImage image = _cache.GetDisplayImage(contact);
					
					try
					{
						if(image != null && image.ImageBuffer != null)
							_contactImageView.InsertFile(image.Filename, PixbufUtility.GetFramedPixbuf(new Gdk.Pixbuf(image.ImageBuffer), PixbufRendererFrameSize.Huge));
					}
					catch
					{
						Log.Debug ("There was an error loading image for contact: "+contact.UniqueIdentifier);
					}
				}
			}
		}
		
		private void RefreshDefaultImages ()
		{
			_defaultImageView.ClearFiles();
			
			foreach (string filename in Directory.GetFiles(Path.Combine(CoreUtility.DataDirectory, "Images")))
			{
				System.IO.FileStream file = System.IO.File.OpenRead (filename);
				
				if (file.Length > 0)
				{
					byte[] fileBytes = new byte[file.Length];
					file.Read (fileBytes, 0, (int)file.Length);
					
					try
					{
						Gdk.Pixbuf pix = new Gdk.Pixbuf(fileBytes);
						
						_defaultImageView.InsertFile(filename, PixbufUtility.GetFramedPixbuf(pix, PixbufRendererFrameSize.Huge));
					}
					catch
					{
						Log.Error("Unable to read file format! Ignoring file.");
					}
				}
				
				file.Close();
			}
		}
		
		private void RefreshOtherImages ()
		{
			_otherImageView.ClearFiles();
			
			string omitDir = _cache.Directory.Substring(_cache.Directory.LastIndexOf("/"));
			
			foreach (string directory in Directory.GetDirectories (Path.Combine(_cache.Directory, "..")))
			{
				// We want to omit this account.
				string thisDir = directory.Substring(directory.LastIndexOf("/"));
				
				if (thisDir == omitDir)
					continue;
				if (!Directory.Exists (Path.Combine(directory, "Images")))
					continue;
				
				foreach (string filename in Directory.GetFiles(Path.Combine(directory, "Images")))
				{
					System.IO.FileStream file = System.IO.File.OpenRead (filename);
					
					if (file.Length > 0)
					{
						byte[] fileBytes = new byte[file.Length];
						file.Read (fileBytes, 0, (int)file.Length);
						
						try
						{
							Gdk.Pixbuf pix = new Gdk.Pixbuf(fileBytes);
							
							_otherImageView.InsertFile(filename, PixbufUtility.GetFramedPixbuf(pix, PixbufRendererFrameSize.Huge));
						}
						catch
						{
							Log.Error("Unable to read file format! Ignoring file.");
						}
					}
					
					file.Close();
				}
			}
		}
		
		public int Run()
		{
			return _dialog.Run();
		}
		
		public void Destroy()
		{
			_dialog.Hide();
			_dialog.Destroy();
		}
		
		private void CheckInput()
		{
			if (_selectedImageFilename == null || _selectedImageFilename == String.Empty)
				_applyButton.Sensitive = false;
			else if (!File.Exists(_selectedImageFilename))
				_applyButton.Sensitive = false;
			else
				_applyButton.Sensitive = true;
		}
	}
}